/*
 * GPUC
 * 
 * Copyright © 2008 Attila T. Áfra <attila.afra@gmail.com>
 * 
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program. If
 * not, see <http://www.gnu.org/licenses/>.
 */

#include <stdlib.h>
#include <GPUC/Main.h>
#include "Shaders.h"
#include "CommonPrivate.h"

/*------------------------------------------------------------------------------------------------*/

GPUC_API GPUC_Error
GPUC_init()
{
    const char *vertexShaderSourceCodeArray[] = {GPUC_vertexShaderSourceCode};
    GLint       parameter;
    GLint       compileStatus;
    GPUC_Error  error;
    int         i;

    if (GPUC_initialized)
        return GPUC_Error_InvalidOperation;

    // Check required extensions
    if (!GLEW_VERSION_2_0 || !GLEW_ARB_texture_rectangle || !GLEW_EXT_framebuffer_object)
    {
        error = GPUC_Error_UnsupportedDevice;
        goto cleanup1;
    }

    // Create kernel vertex shader (1)
    GPUC_vertexShaderId = glCreateShader(GL_VERTEX_SHADER);

    if (GPUC_vertexShaderId == 0)
        return GPUC_Error_Unknown;

    // Compile kernel vertex shader
    glShaderSource(GPUC_vertexShaderId, 1, (const GLchar **)vertexShaderSourceCodeArray, 0);
    glCompileShader(GPUC_vertexShaderId);
    glGetShaderiv(GPUC_vertexShaderId, GL_COMPILE_STATUS, &compileStatus);

    if (compileStatus == GL_FALSE)
    {
        error = GPUC_Error_Unknown;
        goto cleanup1;
    }

    // Create framebuffer object (2)
    glGenFramebuffersEXT(1, &GPUC_framebufferId);
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, GPUC_framebufferId);

    // Get capabilities
    glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB, &parameter);
    GPUC_maxTextureRectSize = (int)parameter;
    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &parameter);
    GPUC_maxTextureImageUnitCount = (int)parameter;
    glGetIntegerv(GL_MAX_DRAW_BUFFERS, &parameter);
    GPUC_maxDrawBufferCount = (int)parameter;

    // Create draw buffer array (3)
    GPUC_drawBuffers = (GLenum *)malloc(GPUC_maxDrawBufferCount * sizeof(GLenum));

    if (GPUC_drawBuffers == 0)
    {
        error = GPUC_Error_OutOfMemory;
        goto cleanup2;
    }

    for (i = 0; i < GPUC_maxDrawBufferCount; ++i)
        GPUC_drawBuffers[i] = GL_COLOR_ATTACHMENT0_EXT + i;

    // Setup
    glDepthMask(GL_FALSE); // ?

    GPUC_objectCount = 0;
    GPUC_initialized = 1;
    GPUC_error = GPUC_Error_None;
    return GPUC_Error_None;

    // Cleanup
/*
cleanup3:
    free(GPUC_drawBufferArray);
*/

cleanup2:
    glDeleteFramebuffersEXT(1, &GPUC_framebufferId);

cleanup1:
    glDeleteShader(GPUC_vertexShaderId);

    return error;
}

/*------------------------------------------------------------------------------------------------*/

GPUC_API GPUC_Error
GPUC_shutdown()
{
    if (!GPUC_initialized || (GPUC_objectCount > 0))
        return GPUC_Error_InvalidOperation;

    free(GPUC_drawBuffers);
    glDeleteFramebuffersEXT(1, &GPUC_framebufferId);
    glDeleteShader(GPUC_vertexShaderId);
    GPUC_initialized = 0;
    GPUC_error = GPUC_Error_NotInitialized;
    return GPUC_Error_None;
}

/*------------------------------------------------------------------------------------------------*/


